메이븐 (소프트웨어)
1. 개요
1. 개요
메이븐은 자바 프로젝트의 빌드 자동화 및 종속성 관리를 위한 도구이다. 2002년에 최초로 등장했으며, 제이슨 반 잔덴과 존 D. 코크가 개발했다. 이 도구는 아파치 라이선스 2.0 하에 배포되는 오픈 소스 소프트웨어이다.
메이븐의 주요 용도는 프로젝트의 빌드, 의존성 관리, 문서화, 배포 과정을 표준화하고 자동화하는 것이다. 이를 통해 개발자는 복잡한 빌드 스크립트 작성에 시간을 덜 쓰고, 실제 소프트웨어 개발에 더 집중할 수 있게 된다.
메이븐은 XML 형식의 설정 파일을 사용하여 프로젝트 구조, 의존하는 라이브러리, 빌드 절차 등을 선언적으로 정의한다. 이는 기존 Ant와 같은 도구가 절차적 스크립트에 의존했던 방식과 대비되는 특징이다. 메이븐은 중앙 리포지토리에서 필요한 라이브러리를 자동으로 다운로드하고 관리하는 강력한 의존성 관리 기능으로 널리 알려져 있다.
2. 역사
2. 역사
메이븐의 개발은 2002년 자카르타 프로젝트의 터빈 서브프로젝트에서 시작되었다. 당시 자바 프로젝트들은 아파치 앤트를 사용해 빌드 과정을 스크립트로 작성했지만, 프로젝트 구조가 표준화되지 않고 복잡한 의존성 관리는 수동으로 이루어져 빌드 파일이 방대해지는 문제가 있었다. 이러한 문제를 해결하기 위해 제이슨 반 잔덴과 존 D. 코크는 더 간결하고 표준화된 접근법을 모색했고, 이 과정에서 메이븐의 초기 버전이 탄생했다.
메이븐은 앤트의 대안이자 발전된 형태로 설계되었으며, 핵심 철학은 "관례에 의한 구성"이다. 이는 개발자가 프로젝트 구조와 빌드 라이프사이클을 미리 정의된 규칙에 따라 구성하면, 복잡한 빌드 스크립트를 작성하지 않아도 된다는 개념이다. 또한 중앙 집중식 리포지토리에서 라이브러리 의존성을 자동으로 해결하는 기능을 도입하여 소프트웨어 개발의 중요한 과제를 해결했다.
2003년에 메이븐 1.0이 출시되었고, 2004년에는 아파치 소프트웨어 재단의 최상위 프로젝트로 승격되었다. 이후 2005년에는 기존 아키텍처의 한계를 극복한 완전히 재설계된 메이븐 2가 등장하며, 플러그인 아키텍처가 크게 개선되고 성능이 향상되어 현재의 표준 기반이 되었다. 메이븐은 자바 생태계에서 프로젝트 빌드, 의존성 관리, 표준화된 프로젝트 구조 제공의 사실상 표준 도구로 자리 잡았다.
3. 핵심 개념
3. 핵심 개념
3.1. 프로젝트 객체 모델 (POM)
3.1. 프로젝트 객체 모델 (POM)
프로젝트 객체 모델은 메이븐의 핵심 구성 파일인 pom.xml을 통해 정의된다. 이 XML 파일은 프로젝트에 대한 모든 구성 정보를 담고 있는 청사진 역할을 한다. pom.xml은 프로젝트의 정체성(예: 그룹 ID, 아티팩트 ID, 버전), 빌드 설정, 의존성 목록, 빌드 플러그인, 프로필, 배포 정보 등을 선언적으로 기술한다. 이 모델 덕분에 개발자는 복잡한 빌드 스크립트를 작성하는 대신, 프로젝트가 무엇인지와 어떻게 빌드되어야 하는지를 선언하는 데 집중할 수 있다.
POM의 구조는 계층적이며 상속을 지원한다. 모든 프로젝트는 최상위에 위치한 슈퍼 POM을 암묵적으로 상속받아 기본적인 빌드 설정과 라이프사이클을 물려받는다. 또한, 다중 모듈 프로젝트에서는 부모 POM을 정의하고 자식 모듈들이 이를 상속받아 공통 설정을 재사용할 수 있다. 이는 대규모 프로젝트에서 중복 구성을 최소화하고 일관성을 유지하는 데 매우 효과적이다.
POM 파일을 통해 정의되는 주요 정보는 다음과 같다.
항목 | 설명 |
|---|---|
프로젝트 좌표 | |
의존성 | 프로젝트가 컴파일 또는 실행 시 필요로 하는 외부 라이브러리 목록. |
빌드 설정 | 소스 코드 디렉토리, 출력 디렉토리, 사용할 플러그인 및 그 설정. |
프로필 | 개발, 테스트, 운영 등 환경에 따라 다른 설정을 적용할 수 있는 프로필 정의. |
이러한 선언적 접근 방식은 메이븐의 가장 큰 장점 중 하나로, 프로젝트 구성이 표준화되고 빌드 과정이 예측 가능해진다. 결과적으로, POM 파일 하나만으로도 프로젝트를 빌드, 테스트, 패키징, 배포하는 데 필요한 모든 정보를 담을 수 있으며, 이는 프로젝트의 이식성과 유지보수성을 크게 향상시킨다.
3.2. 라이프사이클
3.2. 라이프사이클
메이븐의 라이프사이클은 프로젝트를 빌드하고 배포하기 위해 거치는 일련의 단계를 정의한다. 이는 미리 정의된 순서대로 실행되는 빌드 단계들의 집합으로, 개발자가 표준화된 방식으로 프로젝트를 컴파일, 테스트, 패키징, 설치, 배포할 수 있게 해준다. 메이븐의 핵심 목표 중 하나는 빌드 프로세스를 표준화하는 것이며, 라이프사이클은 이 표준의 근간을 이룬다.
메이븐에는 세 가지 기본 라이프사이클이 존재한다. default 라이프사이클은 프로젝트의 배포를 처리하며, clean 라이프사이클은 빌드 시 생성된 파일들을 정리하는 역할을 한다. site 라이프사이클은 프로젝트에 대한 문서 사이트를 생성하고 배포한다. 각 라이프사이클은 여러 개의 페이즈로 구성되어 있으며, 사용자는 특정 페이즈를 실행 명령어로 지정하여 빌드를 진행한다.
가장 일반적으로 사용되는 default 라이프사이클의 주요 페이즈는 다음과 같은 순서를 가진다. validate 페이즈에서는 프로젝트 정보의 정확성을 검증한다. compile 페이즈에서는 프로젝트의 소스 코드를 컴파일한다. test 페이즈에서는 단위 테스트를 실행하며, package 페이즈에서는 컴파일된 코드를 JAR나 WAR 같은 배포 가능한 형식으로 패키징한다. 이후 verify 페이즈에서 통합 테스트 결과를 검증하고, install 페이즈에서 패키지를 로컬 리포지토리에 설치하며, 마지막 deploy 페이즈에서는 원격 리포지토리에 배포를 완료한다.
이러한 라이프사이클과 페이즈 구조는 메이븐의 강력한 기능 중 하나로, 복잡한 빌드 과정을 간단한 명령어(예: mvn clean package)로 실행할 수 있게 한다. 각 페이즈는 순차적으로 실행되며, 특정 페이즈를 실행하면 그 이전의 모든 페이즈도 자동으로 실행된다. 예를 들어 mvn deploy를 실행하면 default 라이프사이클의 deploy 페이즈까지 모든 선행 페이즈가 차례대로 수행된다. 이는 빌드 자동화의 일관성과 신뢰성을 크게 높여준다.
3.3. 의존성 관리
3.3. 의존성 관리
의존성 관리는 메이븐의 핵심 기능 중 하나로, 프로젝트가 필요로 하는 외부 라이브러리(의존성)를 자동으로 다운로드하고 관리하는 체계를 제공한다. 이를 통해 개발자는 각 라이브러리의 JAR 파일을 수동으로 찾아 프로젝트에 추가하는 번거로운 과정 없이, 프로젝트 객체 모델 파일에 간단히 의존성 정보를 선언하는 것만으로 필요한 모든 라이브러리를 통합 관리할 수 있다.
의존성 관리는 중앙 집중식 리포지토리 시스템을 기반으로 한다. 메이븐은 기본적으로 메이븐 중앙 리포지토리에서 라이브러리를 검색하고 다운로드한다. 각 의존성은 groupId, artifactId, version으로 구성된 고유한 좌표로 식별되며, 이 정보를 바탕으로 로컬 캐시와 원격 리포지토리를 검색한다. 필요한 라이브러리가 로컬에 없으면 자동으로 원격 리포지토리에서 다운로드하여 로컬 캐시에 저장함으로써, 동일한 라이브러리를 여러 프로젝트에서 공유하고 재사용할 수 있게 한다.
또한 메이븐은 전이적 의존성을 자동으로 해결한다. 즉, 프로젝트가 직접 선언한 라이브러리 A가 내부적으로 라이브러리 B와 C에 의존할 경우, 메이븐은 A와 함께 B와 C도 자동으로 다운로드하여 프로젝트의 클래스패스에 추가한다. 이 과정에서 발생할 수 있는 의존성 충돌은 의존성 관리 섹션에서 명시적으로 버전을 통제하거나, "가장 가까운 정의 우선" 등의 규칙을 통해 해결한다. 이를 통해 복잡한 라이브러리 간 관계를 명시적으로 관리하지 않아도 된다.
의존성의 범위를 지정하는 기능도 제공한다. compile, provided, runtime, test 등의 스코프를 사용하여, 해당 의존성이 빌드의 어떤 단계에서 필요하고 클래스패스에 포함되어야 하는지를 세밀하게 제어할 수 있다. 예를 들어, test 스코프는 단위 테스트 작성 시에만 사용되는 JUnit 같은 라이브러리에 적용된다. 이러한 체계적인 의존성 관리는 프로젝트의 빌드 결과물을 깔끔하게 유지하고, 배포 과정을 단순화하는 데 기여한다.
3.4. 플러그인
3.4. 플러그인
메이븐의 기능은 플러그인 아키텍처를 중심으로 구성된다. 메이븐 자체는 작은 코어에 불과하며, 모든 실제 작업은 플러그인을 통해 수행된다. 이러한 설계는 메이븐을 매우 확장 가능하게 만든다. 사용자는 자바 컴파일러로 소스를 컴파일하거나, JAR 파일을 생성하고, Javadoc 문서를 만들거나, 단위 테스트를 실행하는 등의 모든 빌드 작업을 플러그인을 통해 실행한다.
플러그인은 하나 이상의 골로 구성되며, 각 골은 특정 작업을 수행하는 단위이다. 예를 들어, maven-compiler-plugin에는 소스 코드를 컴파일하는 compile 골이 있다. 사용자는 라이프사이클의 페이즈에 플러그인 골을 바인딩하여, 특정 페이즈가 실행될 때 원하는 작업이 수행되도록 설정한다. 메이븐은 컨벤션 오버 구성 원칙을 따르므로, 대부분의 일반적인 작업은 플러그인의 기본 설정만으로도 실행 가능하다.
사용자는 POM 파일의 <plugins> 섹션을 통해 프로젝트에 필요한 플러그인을 선언하고 구성할 수 있다. 여기서 플러그인의 버전을 명시하거나, 특정 파라미터를 설정하여 기본 동작을 재정의할 수 있다. 공식적으로 제공되는 수많은 플러그인 외에도, 조직이나 개인이 자체적인 플러그인을 개발하여 빌드 프로세스에 맞춤형 기능을 추가할 수 있다. 이는 메이븐이 다양한 프로젝트 관리 요구사항을 충족시키는 데 핵심적인 역할을 한다.
3.5. 리포지토리
3.5. 리포지토리
메이븐의 리포지토리는 프로젝트 빌드에 필요한 의존성 라이브러리와 플러그인을 저장하고 제공하는 저장소이다. 리포지토리는 크게 로컬 리포지토리와 원격 리포지토리로 구분된다. 로컬 리포지토리는 개발자의 컴퓨터에 위치하며, 한 번 다운로드한 의존성들을 캐시하여 재사용함으로써 빌드 속도를 높이고 네트워크 사용을 줄인다. 기본 위치는 사용자의 홈 디렉토리 내 .m2 폴더이다.
반면 원격 리포지토리는 네트워크를 통해 접근하는 공유 저장소이다. 가장 대표적인 것은 메이븐 중앙 리포지토리로, 아파치 소프트웨어 재단이 관리하며 수많은 오픈 소스 라이브러리를 제공한다. 조직 내부에서 자체적으로 구축하여 사용하는 사설 리포지토리도 있으며, 넥서스 리포지토리 매니저나 JFrog Artifactory와 같은 도구로 관리된다. 사설 리포지토리는 내부 라이브러리를 배포하거나 외부 리포지토리의 의존성을 캐싱하는 프록시 역할을 한다.
메이븐은 프로젝트의 POM 파일에 정의된 의존성을 해결할 때, 먼저 로컬 리포지토리를 확인한다. 필요한 JAR 파일이 로컬에 없으면 설정된 원격 리포지토리 목록(기본값은 메이븐 중앙 리포지토리)을 순서대로 조회하여 다운로드하고 로컬에 저장한다. 이 체계적인 의존성 해결 메커니즘은 프로젝트 빌드의 재현 가능성과 효율성을 보장하는 메이븐의 핵심 기능 중 하나이다.
4. 기본 사용법
4. 기본 사용법
4.1. 프로젝트 생성
4.1. 프로젝트 생성
메이븐에서 새로운 프로젝트를 생성하는 가장 일반적인 방법은 아키타입을 이용하는 것이다. 아키타입은 프로젝트 템플릿으로, 미리 정의된 디렉토리 구조와 기본 설정 파일을 제공한다. 사용자는 mvn archetype:generate 명령어를 실행하여 대화형 모드로 원하는 아키타입을 선택하고, 그룹 ID, 아티팩트 ID, 버전 등의 프로젝트 메타데이터를 입력하면 된다. 이 과정을 통해 표준화된 자바 프로젝트의 골격이 빠르게 생성된다.
생성된 프로젝트의 최상위 디렉토리에는 pom.xml 파일이 위치한다. 이 파일은 프로젝트 객체 모델 (POM)의 핵심으로, 프로젝트의 모든 구성 정보를 담고 있다. 기본적으로 생성된 pom.xml에는 프로젝트의 기본 식별자와 함께, JUnit 같은 필수 테스트 라이브러리에 대한 의존성이 선언되어 있다. 사용자는 이 파일을 수정하여 프로젝트의 빌드 방식을 정의하고, 필요한 의존성을 추가할 수 있다.
메이븐은 프로젝트 생성 시 표준 디렉토리 레이아웃을 따른다. 주요 소스 코드는 src/main/java 디렉토리에, 테스트 코드는 src/test/java 디렉토리에 위치한다. 이 외에도 리소스 파일과 설정 파일을 위한 src/main/resources, 웹 애플리케이션을 위한 src/main/webapp 등의 디렉토리가 자동으로 생성된다. 이 표준 구조는 메이븐의 라이프사이클과 플러그인이 올바르게 동작하는 기반이 된다.
mvn archetype:generate 명령어 대신, 비대화형 방식으로 특정 아키타입을 지정하여 프로젝트를 생성할 수도 있다. 예를 들어, 간단한 자바 프로젝트를 생성하려면 maven-archetype-quickstart 아키타입을, 자바 서블릿 기반의 웹 애플리케이션을 생성하려면 maven-archetype-webapp 아키타입을 사용한다. 이 방법은 CI/CD 파이프라인이나 스크립트에서 프로젝트를 자동 생성할 때 유용하다.
4.2. 빌드 및 패키징
4.2. 빌드 및 패키징
메이븐의 주요 기능은 프로젝트 빌드와 패키징을 자동화하는 것이다. 사용자는 명령줄 인터페이스에서 미리 정의된 라이프사이클 단계를 호출하여 빌드 과정을 실행한다. 가장 일반적으로 사용되는 명령어는 mvn clean package로, 이전 빌드 산출물을 정리한 후 프로젝트를 컴파일하고 테스트하며, 최종적으로 JAR, WAR 같은 패키지 파일을 생성한다. mvn compile은 단순 컴파일만, mvn test는 컴파일과 단위 테스트 실행을 담당한다.
빌드의 구체적인 행위는 프로젝트 객체 모델 파일에 정의된 설정과 연결된 플러그인에 의해 결정된다. 예를 들어, 패키징 단계에서는 프로젝트 객체 모델의 <packaging> 요소 값에 따라 적절한 플러그인이 동작한다. 기본값은 JAR이며, 웹 애플리케이션의 경우 WAR로 설정한다. 이 과정에서 컴파일된 클래스 파일, 리소스 파일, 의존 라이브러리 등이 표준 디렉토리 구조에 따라 묶여 지정된 출력 폴더에 패키징된다.
빌드 과정 중 테스트 실패나 컴파일 오류가 발생하면 라이프사이클은 해당 단계에서 중단된다. 이를 통해 품질 관리가 자동으로 이루어진다. 또한 mvn install 명령을 사용하면 빌드된 패키지를 로컬 메이븐 저장소에 배포하여, 같은 머신의 다른 프로젝트에서 의존성으로 참조할 수 있게 한다. 최종적으로 mvn deploy 명령은 원격 저장소에 패키지를 배포하여 팀 또는 조직 전체와 공유하는 데 사용된다.
4.3. 의존성 추가
4.3. 의존성 추가
메이븐에서 의존성을 추가하는 작업은 프로젝트 객체 모델 파일인 pom.xml 파일을 수정하여 이루어진다. 프로젝트가 필요로 하는 외부 라이브러리(JAR 파일)의 식별 정보를 pom.xml의 <dependencies> 섹션 내에 선언하기만 하면, 메이븐이 이를 자동으로 처리한다. 각 의존성은 그룹 ID, 아티팩트 ID, 버전이라는 세 가지 좌표로 고유하게 식별되며, 필요에 따라 의존성의 스코프를 지정할 수 있다. 스코프는 해당 라이브�러리가 컴파일, 테스트, 런타임 등 어느 단계에서 필요한지를 정의한다.
의존성을 추가할 때 가장 중요한 정보는 해당 라이브러리의 메이븐 좌표이다. 개발자는 중앙 메이븐 중앙 저장소나 기업 내부 넥서스 저장소와 같은 리포지토리에서 필요한 라이브러리의 정확한 좌표를 검색하여 찾을 수 있다. pom.xml에 의존성을 선언하고 빌드 명령을 실행하면, 메이븐은 선언된 리포지토리들을 순차적으로 탐색하여 해당 라이브러리와 그 라이브러리가 다시 필요로 하는 전이 의존성까지 모두 자동으로 다운로드하여 프로젝트의 로컬 저장소에 캐시한다.
이 방식의 가장 큰 장점은 프로젝트에 라이브러리의 바이너리 파일을 직접 포함시키지 않아도 된다는 점이다. pom.xml 파일만으로 모든 의존성을 명시적으로 관리할 수 있어, 프로젝트 설정이 간결해지고 버전 관리 시스템을 통한 협업이 용이해진다. 또한, 중앙 집중식 리포지토리 시스템을 통해 전 세계 개발자들이 동일한 버전의 라이브러리를 공유하고 의존성 충돌을 최소화할 수 있다.
5. 장단점
5. 장단점
메이븐은 자바 생태계에서 널리 채택된 표준 빌드 자동화 도구로서, 일관된 방식으로 프로젝트를 관리하고 빌드할 수 있는 강력한 장점을 제공한다. 가장 큰 장점은 의존성 관리 기능으로, 프로젝트 객체 모델 파일에 필요한 라이브러리를 선언하기만 하면 메이븐이 중앙 리포지토리에서 자동으로 다운로드하고 클래스패스에 포함시킨다. 이는 라이브러리 간의 전이적 의존성까지 자동으로 해결해주어, 개발자가 수동으로 JAR 파일을 관리해야 하는 번거로움을 크게 줄여준다. 또한, 미리 정의된 라이프사이클과 이를 실행하는 플러그인 체계를 통해 컴파일, 테스트, 패키징, 배포와 같은 빌드 과정을 표준화하고 단순화한다. 이러한 일관성 덕분에 새로운 개발자가 프로젝트에 참여하거나, 다른 IDE에서 프로젝트를 열더라도 동일한 방식으로 빌드를 수행할 수 있다.
반면, 메이븐은 유연성이 부족하다는 단점도 지적받는다. 메이븐의 빌드 과정은 라이프사이클과 플러그인에 크게 의존하는데, 표준 플러그인으로 처리하기 어려운 복잡하거나 비표준적인 빌드 작업을 구성하려면 상당한 노력이 필요할 수 있다. XML 기반의 프로젝트 객체 모델 파일은 설정이 장황해질 수 있고, 특히 다중 모듈 프로젝트에서 상속 구조가 복잡해지면 가독성이 떨어질 수 있다. 또한, 의존성 해결을 위해 중앙 리포지토리에 접근해야 하므로, 네트워크가 제한된 환경에서는 빌드 속도가 느려질 수 있으며, 오프라인 모드에서의 작업에도 제약이 따른다.
메이븐의 또 다른 장점은 프로젝트 정보 관리와 보고 기능이다. 프로젝트 객체 모델 파일에 프로젝트명, 버전, 개발자 정보, 라이선스 등을 명시함으로써 프로젝트에 대한 표준화된 메타데이터를 제공한다. 이를 바탕으로 메이븐은 프로젝트 사이트 생성이나 다양한 리포트 생성도 지원한다. 그러나 이러한 강력한 컨벤션 오버 컨피규레이션 철학은 학습 곡선을陡峭하게 만드는 요인이 되기도 한다. 메이븐의 동작 방식을 제대로 이해하지 못하면, 단순한 빌드 설정 변경에도 예상치 못한 문제에 부딪힐 수 있다. 최근에는 그레이들과 같은 더 유연하고 성능이 우수한 빌드 도구들이 등장하며, 특히 대규모 프로젝트나 멀티 플랫폼 프로젝트에서 메이븐의 입지가 도전받고 있다.
6. 대안 및 관련 도구
6. 대안 및 관련 도구
6.1. Gradle
6.1. Gradle
Gradle은 자바를 비롯한 JVM 기반 언어 및 C++, 자바스크립트 등 다양한 언어의 프로젝트를 위한 빌드 자동화 도구이다. Ant와 메이븐의 개념을 기반으로 하지만, Groovy와 Kotlin DSL을 사용하여 선언적이고 유연한 빌드 스크립트를 작성할 수 있도록 설계되었다. 이는 기존의 XML 기반 구성보다 더 간결하고 표현력이 뛰어나며, 빌드 로직을 직접 프로그래밍할 수 있는 강력한 기능을 제공한다.
Gradle의 핵심은 증분 빌드와 빌드 캐시를 통한 높은 성능에 있다. 태스크의 입력과 출력을 추적하여 변경된 부분만 다시 빌드하고, 이전 빌드 결과를 캐시하여 동일한 작업을 반복하지 않음으로써 빌드 시간을 크게 단축한다. 또한 멀티 프로젝트 빌드를 효율적으로 지원하며, 의존성 관리를 위해 메이븐 중앙 저장소 및 JCenter와 같은 외부 리포지토리와의 호환성을 유지한다.
안드로이드 스튜디오의 공식 빌드 시스템으로 채택되면서 널리 알려졌으며, 대규모 엔터프라이즈 프로젝트부터 오픈 소스 라이브러리에 이르기까지 광범위하게 사용된다. 플러그인 생태계가 풍부하여 자바, 코틀린, 스프링 부트, Node.js 등 다양한 프로젝트 유형과 기술 스택을 지원한다.
6.2. Ant
6.2. Ant
Ant는 자바 프로그래밍 언어를 위한 빌드 자동화 도구이다. 아파치 소프트웨어 재단의 프로젝트로 시작되었으며, XML 기반의 빌드 파일을 사용하여 컴파일, 테스트, 패키징, 배포와 같은 반복적인 빌드 작업을 자동화한다. 제이슨 반 잔덴과 존 D. 코크가 초기 개발에 기여했으며, 2002년에 최초로 등장했다.
Ant의 핵심은 build.xml이라는 이름의 빌드 파일이다. 이 파일은 프로젝트의 빌드 과정을 타겟과 태스크라는 단위로 정의한다. 개발자는 이 XML 파일을 작성하여 복잡한 빌드 절차를 스크립트화할 수 있으며, 아파치 라이선스 2.0 하에 배포되어 자유롭게 사용하고 수정할 수 있다.
Ant는 자바 생태계에서 빌드와 배포 과정을 표준화하는 데 크게 기여했으며, 이후 등장한 메이븐과 그레이들과 같은 더 발전된 도구의 기반이 되었다. 특히 이클립스와 같은 통합 개발 환경과의 긴밀한 통합으로 널리 채택되었다.
그러나 XML의 장황한 문법과 복잡한 빌드 파일 관리, 그리고 내장된 의존성 관리 기능의 부재는 한계로 지적되었다. 이러한 단점을 보완하기 위해 의존성 관리를 중점으로 한 메이븐이 등장했으며, 이후 더 유연한 스크립팅을 제공하는 그레이들이 대안으로 부상했다.
